#ifndef __LINUX_SLAB_H__
#define __LINUX_SLAB_H__

#include "linux/mm.h"
#include "linux/list.h"
#include "linux/spinlock.h"

#define BUFCTL_END 0xffffFFFF
#define	SLAB_LIMIT 0xffffFFFE

/*
 * 用于管理 slab 中对象的空闲链表 slab_t 有多少个对象就有多少个 kmem_bufctl_t,
 * 这些kmem_bufctl_t 组成一个数组，紧跟在 slab_t 结构体后面,每个kmem_bufctl_t存储下一个空闲对象的索引
 */
typedef unsigned int kmem_bufctl_t;

/*
 * list: 用于将 slab 链接到 kmem_cache 的 slab 列表中
 * s_mem: 指向 slab 中对象区域的起始地址
 * inuse: 当前 slab 中已分配对象的数量
 * free: 空闲对象的索引
 * 
 * 关于ON-SLAB 和 OFF-SLAB 的区别:
 * ON-SLAB: slab_t 结构体和 kmem_bufctl_t 数组都嵌入在 slab 内存块的起始位置
 * OFF-SLAB: slab_t 结构体和 kmem_bufctl_t 数组单独申请内存放置
 * 
 * 关于slab_t的内存空间布局:
 * ON-SLAB 情况（内部嵌入) 时的内存布局:
 * [slab_t][kmem_bufctl_t数组][对象0][对象1]...[对象N]
 * ^       ^                   ^
 * |       |                   |
 * slabp   空闲数组            对象区域(s_mem指向这里)
 * 
 * 举例：
 * 对象大小：32字节, 每个slab对象数：100个, kmem_bufctl_t：4字节（unsigned int）
 * 
 * 0x1000: [slab_t - 32字节] <- slabp指向这里
 * 0x1020: [kmem_bufctl_t数组 - 400字节] 
 * 0x11A8: [对象0 - 32字节]  <- s_mem指向这里  
 * 0x11C8: [对象1 - 32字节]
 * 
 * 
 * OFF-SLAB 情况（大对象）时的内存布局:
 * 这块内存只包含对象
 * [对象0][对象1]...[对象N]
 * ^
 * |
 * 对象区域(s_mem指向这里)
 * 
 * 单独申请的内存放置slabp和空闲数组
 * [slab_t][kmem_bufctl_t数组]
 * ^       ^                   
 * |       |                   
 * slabp   空闲数组            
 * 
 * 举例：
 * 对象大小：256字节, 每个slab对象数：16个
 * 
 * 0x2000: [对象0 - 256字节] <- s_mem指向这里
 * 0x2100: [对象1 - 256字节]
 * ...
 *  
 * 0xxxxx: [slab_t结构体]    <- slabp指向这里
 * 0xxxxx: [kmem_bufctl_t数组 - 64字节]
 * 
 */
typedef struct slab_s
{
    struct list_head list; 
    void *s_mem;
    unsigned int inuse;
    kmem_bufctl_t free;
} slab_t;

#define slab_bufctl(slabp) ((kmem_bufctl_t *) (((slab_t *)slabp) + 1))

#define CACHE_NAMELEN   20

/*
 * 管理一类具有相同大小和属性的对象缓存
 * slabs: 该缓存中所有 slab 的链表
 * firstnotfull: 指向第一个非满 slab 的指针
 * objsize: 对象大小
 * flags: 创建缓存时的标志
 * num: 每个 slab 中对象的数量
 * spinlock: 保护缓存数据结构的自旋锁
 * gfporder: 分配 slab 时使用的页数
 * gfpflags: 分配 slab 时使用的 GFP 标志
 * slabp_cache: 用于分配 OFF-SLAB 管理结构的缓存
 * growing: 标记缓存是否正在增长
 * dflags: 动态标志，如 DFLGS_GROWN
 * failures: 分配失败的次数
 * name: 缓存名称
 * next: 链接到全局缓存链表
 * cpudata: 每个 CPU 的本地缓存
 * 
 */
typedef struct kmem_cache_s
{
    struct list_head slabs;
    struct list_head *firstnotfull;
    unsigned int objsize;
    unsigned int flags; 
    unsigned int num;   
    spinlock_t spinlock;

#ifdef CONFIG_SMP
    unsigned int batchcount;
#endif

    unsigned int gfporder;

    unsigned int gfpflags;

    struct kmem_cache_s *slabp_cache;
    unsigned int growing;
    unsigned int dflags; 

    unsigned long failures;

    char name[CACHE_NAMELEN];
    struct list_head next;

#ifdef CONFIG_SMP
    cpucache_t *cpudata[NR_CPUS];
#endif

#if STATS
    unsigned long num_active;
    unsigned long num_allocations;
    unsigned long high_mark;
    unsigned long grown;
    unsigned long reaped;
    unsigned long errors;
#ifdef CONFIG_SMP
    atomic_t allochit;
    atomic_t allocmiss;
    atomic_t freehit;
    atomic_t freemiss;
#endif
#endif
} kmem_cache_t;

#define	CFLGS_OFF_SLAB	0x010000UL	
#define	CFLGS_OPTIMIZE	0x020000UL	

#define	DFLGS_GROWN	0x000001UL	

#define	OFF_SLAB(x)	((x)->flags & CFLGS_OFF_SLAB)
#define	OPTIMIZE(x)	((x)->flags & CFLGS_OPTIMIZE)
#define	GROWN(x)	((x)->dlags & DFLGS_GROWN)

#define	SLAB_BUFFER		GFP_BUFFER
#define	SLAB_ATOMIC		GFP_ATOMIC
#define	SLAB_USER		GFP_USER
#define	SLAB_KERNEL		GFP_KERNEL
#define	SLAB_NFS		GFP_NFS
#define	SLAB_DMA		GFP_DMA

#define SLAB_LEVEL_MASK		(__GFP_WAIT|__GFP_HIGH|__GFP_IO)
#define	SLAB_NO_GROW		0x00001000UL	

#define	SLAB_DEBUG_FREE		0x00000100UL // 释放时检查
#define	SLAB_DEBUG_INITIAL	0x00000200UL // 在 slab 初始化时进行调试检查，确保对象初始状态正确
#define	SLAB_RED_ZONE		0x00000400UL // 在每个对象前后添加保护区域（红区），检测缓冲区溢出
#define	SLAB_POISON		    0x00000800UL // 用特定模式填充已释放对象，便于检测使用已释放内存的错误
#define	SLAB_NO_REAP		0x00001000UL // 防止内存紧张时回收该缓存的空
#define	SLAB_HWCACHE_ALIGN	0x00002000UL // 确保对象与硬件缓存行对齐，提高缓存性能
#define SLAB_CACHE_DMA		0x00004000UL // 从DMA可用区域分配内存
#define SLAB_PANIC		    0x00040000UL // Panic if kmem_cache_create() fails
#define SLAB_NOTRACK		0x00000000UL

#define	SLAB_CTOR_CONSTRUCTOR	0x001UL		
#define SLAB_CTOR_ATOMIC	    0x002UL	
#define	SLAB_CTOR_VERIFY	    0x004UL	


//在 struct page 和 kmem_cache_t 之间建立双向关联
#define	SET_PAGE_CACHE(pg,x)  ((pg)->list.next = (struct list_head *)(x))
#define	GET_PAGE_CACHE(pg)    ((kmem_cache_t *)(pg)->list.next)

//在 struct page 和 slab_t 之间建立双向关联
#define	SET_PAGE_SLAB(pg,x)   ((pg)->list.prev = (struct list_head *)(x))
#define	GET_PAGE_SLAB(pg)     ((slab_t *)(pg)->list.prev)


#if STATS
#define	STATS_INC_ACTIVE(x)	((x)->num_active++)
#define	STATS_DEC_ACTIVE(x)	((x)->num_active--)
#define	STATS_INC_ALLOCED(x)	((x)->num_allocations++)
#define	STATS_INC_GROWN(x)	((x)->grown++)
#define	STATS_INC_REAPED(x)	((x)->reaped++)
#define	STATS_SET_HIGH(x)	do { if ((x)->num_active > (x)->high_mark) \
					(x)->high_mark = (x)->num_active; \
				} while (0)
#define	STATS_INC_ERR(x)	((x)->errors++)
#else
#define	STATS_INC_ACTIVE(x)	do { } while (0)
#define	STATS_DEC_ACTIVE(x)	do { } while (0)
#define	STATS_INC_ALLOCED(x)	do { } while (0)
#define	STATS_INC_GROWN(x)	do { } while (0)
#define	STATS_INC_REAPED(x)	do { } while (0)
#define	STATS_SET_HIGH(x)	do { } while (0)
#define	STATS_INC_ERR(x)	do { } while (0)
#endif

#if STATS && defined(CONFIG_SMP)
#define STATS_INC_ALLOCHIT(x)	atomic_inc(&(x)->allochit)
#define STATS_INC_ALLOCMISS(x)	atomic_inc(&(x)->allocmiss)
#define STATS_INC_FREEHIT(x)	atomic_inc(&(x)->freehit)
#define STATS_INC_FREEMISS(x)	atomic_inc(&(x)->freemiss)
#else
#define STATS_INC_ALLOCHIT(x)	do { } while (0)
#define STATS_INC_ALLOCMISS(x)	do { } while (0)
#define STATS_INC_FREEHIT(x)	do { } while (0)
#define STATS_INC_FREEMISS(x)	do { } while (0)
#endif

#define	BYTES_PER_WORD		sizeof(void *)
#define	MAX_OBJ_ORDER	5	/* 32 pages */
#define	MAX_GFP_ORDER	5	/* 32 pages */


# define CREATE_MASK	(SLAB_HWCACHE_ALIGN | SLAB_NO_REAP | SLAB_CACHE_DMA)


void kmem_cache_init(void);
void kmem_cache_sizes_init(void);
void *kmem_cache_alloc(kmem_cache_t *cachep, int flags);
void kmem_cache_free(kmem_cache_t *cachep, void *objp);
void kmem_freepages(kmem_cache_t *cachep, void *addr);
kmem_cache_t *kmem_cache_create(char *name, unsigned int size, unsigned int offset,
                                unsigned long flags, void (*ctor)(void *, kmem_cache_t *, unsigned long),
                                void (*dtor)(void *, kmem_cache_t *, unsigned long));

extern void kfree(void *addr);
extern void *kmalloc(unsigned int size, unsigned int flags);
extern void *kzalloc(unsigned int size, unsigned int flags);

#endif
